import { Ref, ref } from '@vue/composition-api';
import { Screen } from './screen';
import { Map } from './map';
import { INode, Node } from './node';
import { Engine } from './engine';

export class Document {
  engine: Engine;
  screen: Ref<Screen | null>;
  map: Ref<Map | null>;
  nodes: Ref<Node[]>;
  operateNodes: Ref<Node[]>;
  schema: Ref<any>;
  selection: Ref<Node | Map | null>;

  constructor(engine: Engine) {
    this.engine = engine;
    this.screen = ref(null);
    this.map = ref(null);
    this.nodes = ref([]);
    this.operateNodes = ref([]);
    this.schema = ref(null);
    this.selection = ref(null);
  }

  get activeNode() {
    return this.selection;
  }

  init() {

  }

  addNode(node: Node,isOperate:boolean) {
    if(isOperate) {
      this.operateNodes.value.push(node)
    } else {
      this.nodes.value.push(node)
    }
  }

  setMapProps(key: string,value:string) {
    if(this.map.value && this.map.value.props) {
      this.map.value.props[key] = value;
    }
  }

  setScreenProps(key: string,value:string) {
    if(this.screen.value && this.screen.value.props) {
      this.screen.value.props[key] = value;
    }
  }
  // getNodeById(id: string, nodes?:Array<Node>): Node | undefined {
  //   const data = nodes || this.nodes.value;

  //   return data.find(item => item.id === id);
  // }

  setSelection(node: Node | Map | Screen) {
    this.selection.value = node;
  }

  deleteNode(nodeId: string,isOperate:boolean) {
    if (isOperate) {
      this.operateNodes.value = this.operateNodes.value.filter(node => node.id !== nodeId) ?? []
    } else {
      this.nodes.value = this.nodes.value.filter(node => node.id !== nodeId) ?? []
    }
    this.selection.value = null;
  }

  deleteAllNode() {
    this.nodes.value = []
  }
  deleteAllOperateNode() {
    this.operateNodes.value = []
  }
  mergeNodeInfo(id:string,position:{x:number,y:number},isOperate:boolean) {
    if(isOperate) {
      this.operateNodes.value = this.operateNodes.value.map((item)=> {
        if(item.id === id) {
          item.x = position.x;
          item.y = position.y;
        }
        return item;
      })
    } else {
        this.nodes.value = this.nodes.value.map((item)=> {
          if(item.id === id) {
            item.x = position.x;
            item.y = position.y;
          }
          return item;
        })
      }
  }

  setSchema(data: any) {
    const { screen, map, nodes = [], operateNodes = []} = data;

    this.nodes.value = [];
    const assets = this.engine.workbench.assets;
    const assetsComponents = Object.values(assets.components);

    this.nodes.value = nodes.map((schema: INode) => {
      const componentAsset = assetsComponents.find(asset => asset.componentName === schema.componentName)
      const node = new Node({
        ...componentAsset,
        ...schema,
      })
      return node;
    });
    this.operateNodes.value = operateNodes.map((schema: INode) => {
      const componentAsset = assetsComponents.find(asset => asset.componentName === schema.componentName)
      const node = new Node({
        ...componentAsset,
        ...schema,
      })
      return node;
    })

    const mapAssets = assetsComponents.find(asset => asset.componentName === map.componentName);
    this.map.value = new Map({
      ...mapAssets,
      ...map
    })


    const screenAssets = assetsComponents.find(asset => asset.componentName === screen.componentName);
    this.screen.value = new Screen({
      ...screenAssets,
      ...screen
    })
  }

  getSchema() {
    const schema = {
      screen: this.screen.value?.getSchema(),
      map: this.map.value?.getSchema(),
      nodes: this.nodes.value.map(node => node.getSchema()),
      operateNodes: this.operateNodes.value.map(node => node.getSchema()),
    };
    return schema;
  }

  async onChangeSelection(node: Node | null) {
    this.selection.value = node;
  }

  validateNodes(selection?: any){
    let errorNode = null;

    const validator: any = (node: Node) => {
      if (!node.validator()) {
        errorNode = node;
        return false;
      }
      return true;
    };

    const validateStatus = selection ? selection.validator() : this.nodes.value.every(validator);

    return {
      validateStatus,
      errorNode,
    };
  }
}
